package com.emotionalEnvelope.edu.service.impl;

import cn.hutool.core.lang.Validator;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotionalEnvelope.edu.core.RestResponse;
import com.emotionalEnvelope.edu.dto.UserLoginDto;
import com.emotionalEnvelope.edu.mapper.UserMapper;
import com.emotionalEnvelope.edu.model.User;
import com.emotionalEnvelope.edu.param.UserCodeLoginParam;
import com.emotionalEnvelope.edu.param.UserLoginParam;
import com.emotionalEnvelope.edu.param.UserRegisterParam;
import com.emotionalEnvelope.edu.service.IUserService;
import com.emotionalEnvelope.edu.util.MailHelper;
import com.emotionalEnvelope.edu.util.MyTokenUtil;
import com.emotionalEnvelope.edu.util.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author lqq
 * @Date 2023/02/26 20:25
 */
@Slf4j
@Service
public class UserService extends ServiceImpl<UserMapper, User> implements IUserService {
    @Resource
    private UserMapper userMapper;
    @Resource
    private ThreadFactoryBuilder threadFactoryBuilder;
    @Resource
    private RedisTemplate<String, String> redisTemplate;

    static MailHelper helper;

    static {
        try {
            helper = new MailHelper("smtp.qq.com", "2574807195@qq.com", "mpzghvbhybylebjf");
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public RestResponse<UserLoginDto> login(UserLoginParam user) {
        UserLoginDto dto = new UserLoginDto();
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getAccount, user.getAccount())
                .eq(User::getPassword, user.getPassword())
                .or()
                .eq(User::getEmail, user.getAccount())
                .eq(User::getPassword, user.getPassword())
                .last("limit 1");
        User model = userMapper.selectOne(wrapper);
        if (model == null) {
            return RestResponse.failed("账号或密码错误");
        }
        String token = MyTokenUtil.sign(model);
        BeanUtils.copyProperties(model, dto);
        dto.setToken(token);
        return RestResponse.ok(dto, "登录成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResponse<String> register(UserRegisterParam user) {

        User byAccount = userMapper.findByAccount(user.getAccount());
        if (byAccount != null) {
            return RestResponse.failed("注册失败，账号已被注册");
        }
        User model = new User();
        BeanUtils.copyProperties(user, model);
        model.insert();
        return RestResponse.ok("注册成功");
    }

    @Override
    public RestResponse<String> code(String email) {
        if (!StringUtils.hasLength(email)) {
            return RestResponse.failed("邮箱不能为空!");
        }
        boolean isEmail = Validator.isEmail(email);
        if (!isEmail) {
            return RestResponse.failed("邮箱格式不对");
        }
        Map<String, Object> queryMap = new HashMap<>(1);
        queryMap.put("email", email);
        List<User> users = userMapper.selectByMap(queryMap);
        if (users.isEmpty()) {
            return RestResponse.failed("邮箱未被注册！无法发送验证码,请使用已注册邮箱或重新注册");
        }
        String code = String.format("%06d", (int) (Math.random() * 1000000));

        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        ops.set(email, code);
        redisTemplate.expire(code, 5, TimeUnit.MINUTES);
        ThreadPoolExecutor executor = threadFactoryBuilder.newThread();
        executor.execute(() -> {
            try {
                helper.sendMail(email, "[情感信封]服务", "[情感信封]您的验证码为： " + code +
                        "  ,有效期为5分钟,转给他人会导致您的账号被盗和个人信息泄露,谨防诈骗。如非您操作请忽略。");
            } catch (MessagingException e) {
                throw new RuntimeException(e);
            }
        });
        return RestResponse.ok("验证码已发送，请查收！");
    }

    @Override
    public RestResponse<String> loginByCode(UserCodeLoginParam param) {

        if (!StringUtils.hasLength(param.getCode())) {
            return RestResponse.failed("登录失败,请填写验证码");
        }
        String redisCode = redisTemplate.boundValueOps(param.getEmail()).get();
        if (!StringUtils.hasLength(redisCode)) {
            return RestResponse.failed("验证码已过期请重新获取!");
        }
        if (!redisCode.equals(param.getCode())) {
            return RestResponse.failed("验证码不正确,请重新输入!");
        }
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("email", param.getEmail());
        User model = userMapper.selectOne(wrapper);
        redisTemplate.delete(param.getEmail());
        return model != null ? RestResponse.ok("登录成功") : RestResponse.failed("登录失败,无此邮箱");

    }
}
